package repository

import (
	"errors"
	"gin-shop-admin/dao"
	"gin-shop-admin/models"
	"sort"
	"strconv"
	"strings"
)

type PermissionList struct {
	ID int `gorm:"column:ps_id" json:"id"`
	Pid int `gorm:"column:ps_pid" json:"id"`
	Name string `gorm:"column:ps_name" json:"name"`
	Path string `gorm:"column:ps_api_path" json:"path"`
	Order int `gorm:"column:ps_api_order" json:"order"`
	Level int `gorm:"column:ps_level" json:"level"`
}

func GetPermissionList(query string, pageNum int, pageSize int) (total int, permissionList []*PermissionList, err error) {
	if query == "" {
		err = dao.DB.Model(models.Permission{}).Select("sp_permission.ps_id, sp_permission.ps_name,sp_permission_api.ps_api_path, sp_permission.ps_level").Joins("left join sp_permission_api on sp_permission.ps_id = sp_permission_api.ps_id").Limit(pageSize).Offset((pageNum-1)*pageSize).Scan(&permissionList).Error
		dao.DB.Model(models.Permission{}).Select("sp_permission.ps_id, sp_permission.ps_name,sp_permission_api.ps_api_path, sp_permission.ps_level").Joins("left join sp_permission_api on sp_permission.ps_id = sp_permission_api.ps_id").Count(&total)
	}else {
		err = dao.DB.Model(models.Permission{}).Select("sp_permission.ps_id, sp_permission.ps_name,sp_permission_api.ps_api_path, sp_permission.ps_level").Joins("left join sp_permission_api on sp_permission.ps_id = sp_permission_api.ps_id").Where("CONCAT(IFNULL(sp_permission.ps_name, ''), IFNULL(sp_permission_api.ps_api_path,'')) like ?", "%"+query+"%").Limit(pageSize).Offset((pageNum - 1) * pageSize).Scan(&permissionList).Error
		dao.DB.Model(models.Permission{}).Select("sp_permission.ps_id, sp_permission.ps_name,sp_permission_api.ps_api_path, sp_permission.ps_level").Joins("left join sp_permission_api on sp_permission.ps_id = sp_permission_api.ps_id").Where("CONCAT(IFNULL(sp_permission.ps_name, ''), IFNULL(sp_permission_api.ps_api_path,'')) like ?", "%"+query+"%").Count(&total)
	}
	if err != nil {
		return 0, nil, err
	}else {
		return total, permissionList, nil
	}
}

type Menu struct {
	Id int `gorm:"column:ps_id" json:"id"`
	Name string	`gorm:"column:ps_name" json:"name"`
	Pid int `gorm:"column:ps_pid" json:"pid"`
	Path string `gorm:"column:ps_api_path" json:"path"`
	Order int `gorm:"column:ps_api_order;default:null" json:"order"`
	Children []*Menu `json:"children"`
}

func GetMenus() (menu_list []*Menu) {
	var resMenu []*Menu
	query_sql := "SELECT sp.ps_id, sp.ps_name, sp.ps_pid, sp_api.ps_api_path, sp_api.ps_api_order FROM `sp_permission_api` as sp_api " +
		"left join sp_permission as sp on sp. ps_id=sp_api.ps_id "+
		"ORDER BY sp_api.ps_api_order;"
	dao.DB.Raw(query_sql).Scan(&resMenu)
	menu_list = GetMenuTree(resMenu)
	return
}

func GetMenuTree(resList []*Menu) (menu_list []*Menu) {
	var menu_map map[int]*Menu
	menu_map = make(map[int]*Menu)
	for _, row := range resList{
		menu_map[row.Id] = row
	}
	var top_menu_ids []int
	for _, row := range resList{
		if row.Pid != 0 {
			menu_map[row.Pid].Children = append(menu_map[row.Pid].Children, row)
		}else{
			top_menu_ids = append(top_menu_ids, row.Id)
		}
	}
	for _, id := range top_menu_ids{
		menu_list = append(menu_list, menu_map[id])
	}
	return
}

func GetUserMenus(user_id int) (role_perm []*RolePermission, api_path_map map[string]bool, err error) {
	var role []*models.Role
	query_sql := "SELECT r.role_id, r.ps_ids FROM `sp_manager` as m join sp_role as r on m.role_id=r.role_id where m.mg_id=? limit 1"
	if err := dao.DB.Raw(query_sql, user_id).Scan(&role).Error; err!= nil{
		return nil, nil, err
	}
	role_perm, api_path_map = GetRoleMenus(role[0])
	return
}


type PermissionTree struct {
	ID int `json:"id"`
	AuthName string `json:"authName"`
	Path string `json:"path"`
	Pid int `gorm:"column:ps_pid" json:"pid"`
	Order int `gorm:"column:ps_api_order" json:"order"`
	Children []interface{} `json:"children"`
}

type RolePermission struct {
	ID int `json:"id"`
	AuthName string `json:"authName"`
	Path string `json:"path"`
	Order int `json:"order"`
	Children []interface{} `json:"children"`
}

type RoleInfo struct {
	ID int `json:"id"`
	RoleName string `json:"roleName"`
	RoleDesc string `json:"roleDesc"`
	Children []*RolePermission `json:"children"`
}

type PermissionResult struct {
	Id int `gorm:"column:ps_id" json:"id"`
	Pid int `gorm:"column:ps_pid" json:"pid"`
	Name string	`gorm:"column:ps_name" json:"name"`
	Path string `gorm:"column:ps_api_path" json:"path"`
	Order int `gorm:"column:ps_api_order" json:"order"`
	Level string `gorm:"column:ps_level" json:"level"`
}

func GetRolesList() (role_list []*RoleInfo, err error) {
	var roles []*models.Role
	if err = dao.DB.Model(models.Role{}).Find(&roles).Error; err!=nil{
		return nil, err
	}
	for _, role := range roles{
		roleInfo := &RoleInfo{ID:role.ID,RoleName:role.Name,RoleDesc:role.Desc}
		roleInfo.Children = GetRolePermissions(role)
		role_list = append(role_list, roleInfo)
	}
	return
}

func GetRolePermissions(role *models.Role) (role_permissions []*RolePermission)  {
	query_sql := "SELECT sp.ps_id, sp.ps_pid, sp.ps_name, sp_api.ps_api_path, sp_api.ps_api_order, sp.ps_level FROM `sp_permission_api` as sp_api left join sp_permission as sp on sp. ps_id=sp_api.ps_id where sp.ps_id in (?)"
	var permissions []*PermissionList
	pids := strings.Split(role.Pids, ",")
	dao.DB.Raw(query_sql, pids).Scan(&permissions)
	role_permissions = getRolePermissionTree(permissions)
	return
}

func GetRoleMenus(role *models.Role) (role_permissions []*RolePermission, api_path_map map[string]bool)  {
	query_sql := "SELECT sp.ps_id, sp.ps_pid, sp.ps_name, sp_api.ps_api_path, sp_api.ps_api_order, sp.ps_level FROM `sp_permission_api` as sp_api left join sp_permission as sp on sp. ps_id=sp_api.ps_id where sp.ps_id in (?)"
	var permissions []*PermissionList
	pids := strings.Split(role.Pids, ",")
	dao.DB.Raw(query_sql, pids).Scan(&permissions)
	role_permissions, api_path_map = getRoleMenuTree(permissions)
	return
}

func GetAllPermissionsTree() (permissionsTreeList []*PermissionTree) {
	query_sql := "SELECT sp.ps_id, sp.ps_pid, sp.ps_name, sp_api.ps_api_path, sp.ps_level FROM `sp_permission_api` as sp_api left join sp_permission as sp on sp. ps_id=sp_api.ps_id"
	var permissions []*PermissionList
	dao.DB.Raw(query_sql).Scan(&permissions)
	permissionsTreeList = getPermissionTree(permissions)
	return permissionsTreeList
}

func getPermissionTree(permissions []*PermissionList)(permissionsTreeList []*PermissionTree)  {
	permission_map := make(map[int]*PermissionTree)
	for _, per := range permissions {
		permission_map[per.ID] = &PermissionTree{ID: per.ID, AuthName: per.Name, Path: per.Path, Pid:per.Pid, Order:per.Order}
	}
	for _, perm := range permissions{
		if perm.Level != 0{
			permission_map[perm.Pid].Children = append(permission_map[perm.Pid].Children, permission_map[perm.ID])
		}
	}
	for _, perms := range permissions {
		if perms.Level == 0 {
			permissionsTreeList = append(permissionsTreeList, permission_map[perms.ID])
		}
	}
	return
}

// 获取角色权限列表
func getRolePermissionTree(permissions []*PermissionList)(role_permissions []*RolePermission)  {
	permission_map := make(map[int]*RolePermission)
	top_menu_order_map := make(map[int]int)
	var top_order_list []int
	for _, per := range permissions {
		permission_map[per.ID] = &RolePermission{ID: per.ID, AuthName: per.Name, Path: per.Path, Order:per.Order}
	}
	for _, perm := range permissions{
		if perm.Level != 0{
			permission_map[perm.Pid].Children = append(permission_map[perm.Pid].Children, permission_map[perm.ID])
		}else {
			top_order_list = append(top_order_list, perm.Order)
			top_menu_order_map[perm.Order] = perm.ID
		}
	}
	sort.Ints(top_order_list)
	for _, order := range top_order_list{
		role_permissions = append(role_permissions, permission_map[top_menu_order_map[order]])
	}
	return
}

func getRoleMenuTree(permissions []*PermissionList)(role_permissions []*RolePermission, api_path_map map[string]bool)  {
	permission_map := make(map[int]*RolePermission)
	top_menu_order_map := make(map[int]int)
	var top_order_list []int
	for _, per := range permissions {
		permission_map[per.ID] = &RolePermission{ID: per.ID, AuthName: per.Name, Path: per.Path, Order:per.Order}
	}
	api_path_map = make(map[string]bool)
	for _, perm := range permissions{
		if perm.Level != 0{
			permission_map[perm.Pid].Children = append(permission_map[perm.Pid].Children, permission_map[perm.ID])
			api_path_map["/" + perm.Path] = true
		}else {
			top_order_list = append(top_order_list, perm.Order)
			top_menu_order_map[perm.Order] = perm.ID
		}
	}
	sort.Ints(top_order_list)
	for _, order := range top_order_list{
		role_permissions = append(role_permissions, permission_map[top_menu_order_map[order]])
	}
	return
}

func DeleteRolePermission(roleID int, permissionID string) (role *models.Role, err error) {
	role = new(models.Role)
	if err := dao.DB.Where(&models.Role{ID: roleID}).First(&role).Error; err != nil {
		return nil, err
	}
	var permissionList []*models.Permission
	var pids_list []int
	perID, _ := strconv.Atoi(permissionID)
	pids_list = append(pids_list, perID)
	dao.DB.Select("ps_id").Where(models.Permission{Pid: perID}).Find(&permissionList)
	if len(permissionList) > 0 {
		for _, permission := range permissionList {
			var permissions []*models.Permission
			pids_list = append(pids_list, permission.ID)
			dao.DB.Select("ps_id").Where(models.Permission{Pid: permission.ID}).Find(&permissions)
			if len(permissions) > 0 {
				for _, permission := range permissions {
					pids_list = append(pids_list, permission.ID)
				}
			}
		}
	}

	var pids string
	pids = role.Pids
	for _, pid := range pids_list {
		pid_str := strconv.Itoa(pid)
		index := strings.Index(pids, pid_str)
		if index != -1 {
			if index == 0 {
				if len(pids) == 3 {
					pids = strings.Replace(pids, pid_str, "", 1)
				} else {
					pids = strings.Replace(pids, pid_str+",", "", 1)
				}
			} else {
				pids = strings.Replace(pids, ","+pid_str, "", 1)
			}
		}
	}
	if role.Pids == pids {
		return nil, errors.New("此权限不存在")
	}else {
		if err := dao.DB.Model(&role).Update(models.Role{Pids: pids}).Error; err != nil {
			return nil, err
		}
		return role, nil
	}
}

func UpdateRolePermission(roleID int, permission_ids string) (err error) {
	return dao.DB.Model(models.Role{}).Where(&models.Role{ID:roleID}).Update(models.Role{Pids:permission_ids}).Error
}